import json
import traceback
from sched import scheduler

import redis
from apscheduler.schedulers.background import BackgroundScheduler

# Create your views here.
from apscheduler.triggers.cron import CronTrigger
from django.db import transaction

from rest_framework import viewsets

from apiTest.case_runnning import logging
from apiTest.models import TestCaseGroup, TestCaseGroupResult, TestCaseResult, ApiRequestResult
from apiTest.serializers import TestCaseGroupResultModelSerializer, TestCaseResultModelSerializer, \
    ApiRequestResultModelSerializer
from common.paginatedViewMixin import PaginatedViewMixin
from common.standard_pagination import StandardPagination
from task.models import TaskInfo, TaskLog
from task.scheduler import SchedulerSingleton
from task.serializers import TaskInfoModelSerializer, TaskLogModelSerializer, TaskLogDetailsSerializer
from task.task_running import task_run
from utils import response_body_utils
from utils.cron_expression import is_valid_cron_expression
from utils.response_body_utils import get_success_response, get_error_response


class TaskInfoView(viewsets.GenericViewSet, PaginatedViewMixin):
    queryset = TaskInfo.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TaskInfoModelSerializer
    SchedulerSingleton()
    pagination_class = StandardPagination  # 使用自定义的分页类

    def add(self, request):
        scheduler_instance = SchedulerSingleton()
        name = request.data["name"]
        project_id = request.data["project_id"]
        if self.get_queryset().filter(name=name, project_id=project_id).first():
            return get_error_response(response_body_utils.DATA_DUPLICATION)
        else:
            # 判断是否存在cron格式是否存在且格式是否正常
            if request.data.get("cron_expression") and is_valid_cron_expression(request.data.get("cron_expression")):
                serializer = self.get_serializer(data=request.data)
                if serializer.is_valid():
                    task_info = serializer.save()
                    scheduler_instance.scheduler.add_job(task_run, next_run_time=None,
                                                         trigger=CronTrigger.from_crontab(
                                                             task_info.cron_expression),
                                                         id=str(task_info.id), args=(serializer.data,))
                    logging.info("所有task：{}".format(scheduler_instance._scheduler.get_jobs()))
                    if task_info.status:
                        scheduler_instance.resume_task(str(task_info.id))
                else:
                    print(serializer.errors)
                return get_success_response("")
            else:
                return get_error_response(response_body_utils.CRON_EXPRESSION_EXCEPTION)

    def details(self, request, **kwargs):
        if kwargs.get("pk"):
            data = TaskInfo.objects.get(id=kwargs["pk"])
            data = TaskInfoModelSerializer(data).data
            return get_success_response(data)

    def page(self, request):
        get_queryset = self.get_queryset()
        if request.query_params.get("project_id"):
            get_queryset = get_queryset.filter(project_id=request.query_params.get("project_id"))
        return super().base_page(request, get_queryset)

    def run(self, request, **kwargs):
        task_id = kwargs["pk"]
        task_info = self.get_queryset().get(id=task_id)
        task_info = self.get_serializer(task_info).data
        if not task_info["status"] and task_info["cron_expression"]:
            task_run(task_info)
        return get_success_response("")

    def resume(self, request, **kwargs):
        scheduler_instance = SchedulerSingleton()
        task_id = kwargs["pk"]
        self.get_queryset().filter(id=task_id).update(status=1)
        scheduler_instance.resume_task(str(task_id))
        return get_success_response("")

    def pause(self, request, **kwargs):
        scheduler_instance = SchedulerSingleton()
        task_id = kwargs["pk"]
        self.get_queryset().filter(id=task_id).update(status=0)
        scheduler_instance.pause_task(str(task_id))
        return get_success_response("")

    def delete(self, request, **kwargs):
        scheduler_instance = SchedulerSingleton()
        if kwargs.get("pk"):
            self.get_queryset().filter(id=kwargs["pk"]).update(is_deleted=1)
            scheduler_instance.remove_task(str(kwargs["pk"]))
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def update(self, request):
        scheduler_instance = SchedulerSingleton()
        req_data = request.data
        if req_data.get("id"):
            try:
                with transaction.atomic():
                    self.get_queryset().filter(id=req_data.get("id")).update(name=req_data.get("name"),
                                                                             env_id=req_data.get("env_id"),
                                                                             cron_expression=req_data.get(
                                                                                 "cron_expression"),
                                                                             remark=req_data.get("remark"),
                                                                             status=req_data.get("status"),
                                                                             is_send_email=req_data.get(
                                                                                 "is_send_email"),
                                                                             is_send_ding_ding=req_data.get(
                                                                                 "is_send_ding_ding"),
                                                                             email_list=json.dumps(
                                                                                 req_data.get("email_list")))
                    task = TaskInfo.objects.get(id=req_data.get("id"))
                    group_list = TestCaseGroup.objects.all().filter(id__in=req_data.get("group_id_list"))
                    task.group_id_list.clear()
                    for group in group_list:
                        task.group_id_list.add(group)
                    if not req_data.get("status"):
                        scheduler_instance.pause_task(str(req_data.get("id")))
                    else:
                        scheduler_instance.pause_task(str(req_data.get("id")))
                    scheduler_instance.modify_task(str(req_data.get("id")), request.data["cron_expression"])
                    return get_success_response("")
            except (Exception, AssertionError) as e:
                logging.error(f"An error occurred: {e}")
                traceback.print_exc()
                return get_error_response(response_body_utils.SYSTEM_EXCEPTION)
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def modify(self, request):
        scheduler_instance = SchedulerSingleton()
        task_id = request.data["id"]
        self.get_queryset().filter(id=task_id).update(cron_expression=request.data["cron_expression"])
        scheduler_instance.modify_task(str(task_id), request.data["cron_expression"])
        return get_success_response("")


class TaskLogView(viewsets.GenericViewSet, PaginatedViewMixin):
    queryset = TaskLog.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TaskLogModelSerializer
    pagination_class = StandardPagination  # 使用自定义的分页类

    def page(self, request):
        get_queryset = self.get_queryset()
        if request.query_params.get("project_id"):
            get_queryset = get_queryset.filter(project_id=request.query_params.get("project_id"))
        return super().base_page(request, get_queryset)


class TaskLogDetailsView(viewsets.GenericViewSet):
    queryset = TaskLog.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TaskLogDetailsSerializer

    def details(self, request, **kwargs):
        if kwargs.get("pk"):
            data = TaskLog.objects.get(id=kwargs["pk"])
            data = self.get_serializer(data).data
            group_result_list = TestCaseGroupResult.objects.filter(task_log_id=kwargs["pk"], is_deleted=0)
            group_result_list = TestCaseGroupResultModelSerializer(group_result_list, many=True).data
            group_result_end_list = []
            for group_result in group_result_list:
                test_result_list = TestCaseResult.objects.filter(task_log_id=kwargs["pk"], is_deleted=0,
                                                                 group_id=group_result["test_case_group_id"])
                test_result_list = TestCaseResultModelSerializer(test_result_list, many=True).data
                test_result_end_list = []
                for test_result in test_result_list:
                    api_request_result_list = ApiRequestResult.objects.filter(task_log_id=kwargs["pk"], is_deleted=0,
                                                                              api_test_case_id=test_result[
                                                                                  "test_case_id"],
                                                                              test_case_group_id=group_result[
                                                                                  "test_case_group_id"])
                    api_request_result_list = ApiRequestResultModelSerializer(api_request_result_list, many=True).data
                    if test_result["step_fail_results"] == 0:
                        test_result["result_status"] = True
                    else:
                        test_result["result_status"] = False
                    test_result["api_request_result_list"] = api_request_result_list
                    test_result_end_list.append(test_result)
                group_result["test_result_list"] = test_result_end_list
                if group_result["test_case_failed_result"] == 0:
                    group_result["result_status"] = True
                else:
                    group_result["result_status"] = False
                group_result_end_list.append(group_result)
            data["group_result_list"] = group_result_end_list
            data = self.get_serializer(data).data
            return get_success_response(data)
